
import time
import requests
import psycopg2 as pssql
import pymysql as mysql
from sanic.response import json
from applications.configs import  CONFIG
from loguru import logger
from functools import wraps

def check_identity(token, appi_name):
    url = CONFIG.authorization_url
    headers = {'Authorization': token, 'AppName': appi_name}
    # logger.info('headers: ', headers)
    res = requests.get(url=url, headers=headers).json()
    if res.get('code')==200:
        logger.success(res)
    else:
        logger.warning(res)
    return res


def find_value(jsdata):
    val_list = []
    for k in jsdata.keys():
        p = jsdata[k]
        if type(p) == dict:
            val_list += find_value(p)
        elif type(p) == list or type(p) == set or type(p) == tuple:
            val_list += list(p)
        else:
            val_list.append(p)
    return val_list


def check_params(request):
    in_param = find_value(request.json)
    paramstr = ''
    for s in in_param:
        paramstr += str(s).lower() + '/'
    # logger.info('parameter:{}', paramstr)
    invalied_str = ["--", "select", "end", "delete", "update", "set", "drop", 'truncate', 'alter']
    for inval in invalied_str:
        if inval in paramstr:
            return 0x01
    if "'" in paramstr:
        cnt = paramstr.count("'")
        if cnt % 2 == 0:
            pass
        else:
            return 0x01
    return 0x00

def protect(func):
    async def wrapper(request):
        if check_params(request) == 0x01:
            return json(
                {'message': '恶意参数'},
                status=414
            )
        else:
            ret = await func(request)
            return ret

    return wrapper


def api_trace(bp,route=''):
    '''接口访问追踪

    :param bp:
    :param route:
    :param track: 是否开启接口访问记录
    :return:
    '''
    def decorator(func):
        @wraps(func)
        async def decorated_function(request,*args, **kwargs):
            bp_url_prefix=bp.url_prefix
            if len(route)==0:
                api_route = func.__name__
            else :
                api_route=route
            edismanage_check_name = CONFIG.app_name  + bp_url_prefix+ api_route
            userempno = request.cookies.get('username', None)
            request.headers['username'] = userempno

            if userempno:
                # user track information
                source_ip = request.headers['x-forwarded-for']
                # api performances information
                bg_time = time.time()
                req_time_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
                if check_params(request) == 0x01:
                    return json({'message': '恶意参数'},status=403)
                params = str(request.json)
                # execute api function
                ret = await func(request)
                ret_status = ret.status
                # api performances information
                ed_time = time.time()
                ret_time_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
                act_time = ed_time - bg_time
                # logger.info((service_name, bg_time_str, ed_time_str, process_time, user_id, user_ip))
                # information insert into database
                db = DB()
                try:
                    # 创建插入SQL语句
                    query = """
                    INSERT INTO {} ({})
                    VALUES ({}) """
                    tar_str = ''
                    val_str = ''
                    for tar in CONFIG.tracker_cols:
                        tar_str += tar + ', '
                        val_str += '%s, '
                    tar_str = tar_str[:-2]
                    val_str = val_str[:-2]
                    sql_insert_cmd1 = query.format(CONFIG.tracker_table, tar_str, val_str)
                    sql_insert_cmd2 = sql_insert_cmd1 % (
                    CONFIG.app, edismanage_check_name, CONFIG.app_url, params, req_time_str, ret_status, ret_time_str, act_time, userempno,
                    source_ip)
                    # logger.debug(sql_insert_cmd2)
                    # db.cursor.execute(sql_insert_cmd2)
                    # db.cursor.execute(sql_insert_cmd2)
                    db.cursor.execute(
                        sql_insert_cmd1,
                        (CONFIG.app, edismanage_check_name, CONFIG.app_url, params, req_time_str, ret_status, ret_time_str, act_time,
                        userempno,source_ip))
                    # 关闭游标
                    db.cursor.close()
                    db.conn.commit()
                    # logger.success(' api trace success')
                except Exception as e:
                    logger.exception(e)
                    # raise e
                    return json({'message': '接口访问追踪出错'}, status=500)
            ret = await func(request,*args, **kwargs)
            # return json({})
            return ret
        return decorated_function
    return decorator
#mly
def authority(bp,route='',track=False):
    '''可传参的权限装饰器

    :param bp:
    :param route:
    :param track: 是否开启接口访问记录
    :return:
    '''
    def decorator(func):
        @wraps(func)
        async def decorated_function(request,*args, **kwargs):
            bp_url_prefix=bp.url_prefix
            if len(route)==0:
                api_route = func.__name__
            else :
                api_route=route
            edismanage_check_name = CONFIG.app_name  + bp_url_prefix+ api_route

            check_res = check_identity(request.headers.get('Authorization'), edismanage_check_name)
            if check_res['code']!= 200:
                logger.info(edismanage_check_name)
                return json(check_res, status=check_res['code'])
            else:
                check_auth_res=check_res['data']['result']

                username = check_res['data']['username']
            request.headers['username'] = username
            if check_auth_res:
                ret = await func(request,*args, **kwargs)
                return ret
            else:
                return json({'message': '用户无权限'}, status=403)
        return decorated_function
    return decorator